/*
    COMP9517 Computer Vision, Semester 2, 2011 - University of New South Wales
   ============================================================================
   |   Group .  | Christian Mostegel & Dong Back Kim                          |
   ============================================================================
 */

#ifndef ANALYSER_H
#define ANALYSER_H

#include "PointCloud.h"
#include "Camera.h"
#include "AnalyzedImage.h"
#include "Track.h"
#include "opencv2/opencv.hpp"
#include "Parameters.h"

class Analyser
{

private:

    QList<Camera>   m_cameras;
    PointCloud      m_point_cloud;
    PointCloud      m_test_cloud;
    QList<QString>  m_files;
    QList<int>      m_initial_files;
    QList<Parameters> m_test_parameters;
    QList<unsigned int > m_test_counter;

    QList<AnalyzedImage* > m_images;
    QList<Track* > m_tracks;
    QList<Track* > m_test_tracks;
    cv::Mat m_track_matrix;
    QList<Parameters* > m_parameters;
    QList<unsigned int> m_relevance;
    cv::Mat m_object_center;
    double m_max_distance;
    unsigned long m_total_number_of_consistently_cross_checked_matches;
    unsigned long m_total_number_of_consistent_RANSAC_matches;
    unsigned int m_num_inliers;
    unsigned int m_num_soft_inliers;
    unsigned int m_num_outliers;

    unsigned long m_sum_track_size_inliers;
    unsigned long m_sum_track_size_soft_inliers;
    unsigned long m_sum_track_size_outliers;

    void rejectOutliers();

    QList<unsigned int> m_notre_dame_file_selection;

    void matches2points(const std::vector<cv::KeyPoint>& train, const std::vector<cv::KeyPoint>& query,
                            const std::vector<cv::DMatch>& matches, std::vector<cv::Point2f>& pts_train,
                            std::vector<cv::Point2f>& pts_query);
    void matches2points(const std::vector<cv::KeyPoint>& train, const std::vector<cv::KeyPoint>& query,
                                  const std::vector<cv::DMatch>& matches, std::vector<cv::Point2f>& pts_train,
                                  std::vector<cv::Point2f>& pts_query, cv::Mat & Ktrain, cv::Mat & Kquery);
    QPair<unsigned int, unsigned int> getPairWithMostMatches();
    cv::Mat createSkewSymmetricMatrix(cv::Vec3d vec);
    void extractTracks();
    void init3DModel();
    QList<unsigned int> getJoinedTracks(int ind1,int ind2);
    void estimateObjectCenter(unsigned int img_ind1,unsigned int img_ind2);
    void estimate3DPoints(unsigned int img_ind1,unsigned int img_ind2);
    void estimate3DPointsNormalized(unsigned int img_ind1,unsigned int img_ind2);
    void estimate3DPointsNormalizedParallel(unsigned int img_ind1,unsigned int img_ind2 );
    void estimate3DPointsNormalizedNotreDame(unsigned int img_ind1,unsigned int img_ind2, QList<unsigned int> & track_ids);
    void test3DProjection();
    void print(cv::Mat mat);
    void correctF(cv::Mat & F);
    bool loadParameters(QString folder_path);
    bool endingEquals(std::string query_name, std::string ending);
    std::string getParameterFileName(std::string dir, std::string file_ending);
    void init3DModel(int mode);
    void bundleAdjust(int ba_mode = 0);
    QList<unsigned int>  getInitialisedImageIds();
    int getMostRelevantImageID();
    void addImageToModel(int img_id);
    void getCorrespondences(int img_id,cv::Mat & X,cv::Mat & Y,cv::Mat & W,cv::Mat & A);
    int getClosestImageID(int img_id);
    void produceCameras();
    void addNewTracksToModel(int img_id);
    void printPointCloud();
    void loadNotreDameImages();
    void estimateAll3DPoints();

    int m_calls_ctr;

public:

    void evaluateMatchingAccuracy();
    void testNotreDame();

    QList<Camera> getCameras() const { return m_cameras; }
    PointCloud getPointCloud() const { return m_point_cloud; }

public:

    Analyser(const QList<QString> & files, const QList<int> & initList);

    QList<int> getInitialFileIdx() { return m_initial_files; }

    void analyse(); // Christian's implementation begins here
};

#endif // ANALYSER_H
